home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 4 / Apprentice-Release4.iso / Source Code / C / Applications / Python 1.3 / source code / Tools / freeze / freeze.py < prev    next >
Encoding:
Python Source  |  1995-12-17  |  7.4 KB  |  301 lines  |  [TEXT/R*ch]

  1. #! /usr/local/bin/python
  2.  
  3. # "Freeze" a Python script into a binary.
  4. # Usage: see variable usage_msg below (before the imports!)
  5.  
  6. # HINTS:
  7. # - Edit the lines marked XXX below to localize.
  8. # - Make sure the #! line above matches the localizations.
  9. # - You must have done "make inclinstall libainstall" in the Python
  10. #   build directory.
  11. # - The script name should end in ".py".
  12. # - The script should not use dynamically loaded modules
  13. #   (*.so on most systems).
  14.  
  15.  
  16. # Usage message
  17.  
  18. usage_msg = """
  19. usage: freeze [-p prefix] [-P exec_prefix] [-e extension] script [module] ...
  20.  
  21. -p prefix:    This is the prefix used when you ran
  22.               'Make inclinstall libainstall' in the Python build directory.
  23.               (If you never ran this, freeze won't work.)
  24.               The default is /usr/local.
  25.  
  26. -P exec_prefix: Like -p but this is the 'exec_prefix', used to
  27.         install objects etc.  The default is the value for -p.
  28.  
  29. -e extension: A directory containing additional .o files that
  30.               may be used to resolve modules.  This directory
  31.               should also have a Setup file describing the .o files.
  32.               More than one -e option may be given.
  33.  
  34. script:       The Python script to be executed by the resulting binary.
  35.           It *must* end with a .py suffix!
  36.  
  37. module ...:   Additional Python modules (referenced by pathname)
  38.               that will be included in the resulting binary.  These
  39.               may be .py or .pyc files.
  40.  
  41. NOTES:
  42.  
  43. In order to use freeze successfully, you must have built Python and
  44. installed it.  In particular, the following two non-standard make
  45. targets must have been executed:
  46.  
  47.     make inclinstall
  48.     make libainstall        # Note: 'liba', not 'lib'
  49.  
  50. The -p and -P options passed into the freeze script must correspond to
  51. the --prefix and --exec-prefix options passed into Python's configure
  52. script.
  53. """
  54.  
  55.  
  56. # XXX Change the following line to point to your Tools/freeze directory
  57. PACK = '/ufs/guido/src/python/Tools/freeze'
  58.  
  59. # XXX Change the following line to point to your install prefix
  60. PREFIX = '/usr/local'
  61.  
  62. # XXX Change the following line to point to your install exec_prefix
  63. EXEC_PREFIX = None            # If None, use -p option for default
  64.  
  65.  
  66. # Import standard modules
  67.  
  68. import cmp
  69. import getopt
  70. import os
  71. import string
  72. import sys
  73. import addpack
  74.  
  75.  
  76. # Set the directory to look for the freeze-private modules
  77.  
  78. dir = os.path.dirname(sys.argv[0])
  79. if dir:
  80.     pack = dir
  81. else:
  82.     pack = PACK
  83. addpack.addpack(pack)
  84.  
  85.  
  86. # Import the freeze-private modules
  87.  
  88. import checkextensions
  89. import findmodules
  90. import makeconfig
  91. import makefreeze
  92. import makemakefile
  93. import parsesetup
  94.  
  95.  
  96. # Main program
  97.  
  98. def main():
  99.     # overridable context
  100.     prefix = PREFIX            # settable with -p option
  101.     exec_prefix = None        # settable with -P option
  102.     extensions = []
  103.     path = sys.path
  104.  
  105.     # output files
  106.     frozen_c = 'frozen.c'
  107.     config_c = 'config.c'
  108.     target = 'a.out'        # normally derived from script name
  109.     makefile = 'Makefile'
  110.  
  111.     # parse command line
  112.     try:
  113.         opts, args = getopt.getopt(sys.argv[1:], 'e:p:P:')
  114.     except getopt.error, msg:
  115.         usage('getopt error: ' + str(msg))
  116.  
  117.     # proces option arguments
  118.     for o, a in opts:
  119.         if o == '-e':
  120.             extensions.append(a)
  121.         if o == '-p':
  122.             prefix = a
  123.         if o == '-P':
  124.             exec_prefix = a
  125.     
  126.     # default exec_prefix
  127.     if exec_prefix is None:
  128.         exec_prefix = EXEC_PREFIX
  129.         if exec_prefix is None:
  130.             exec_prefix = prefix
  131.  
  132.     # locations derived from options
  133.     binlib = os.path.join(exec_prefix, 'lib/python/lib')
  134.     incldir = os.path.join(prefix, 'include/Py')
  135.     config_c_in = os.path.join(binlib, 'config.c.in')
  136.     frozenmain_c = os.path.join(binlib, 'frozenmain.c')
  137.     getpath_c = os.path.join(binlib, 'getpath.c')
  138.     supp_sources = [frozenmain_c, getpath_c]
  139.     makefile_in = os.path.join(binlib, 'Makefile')
  140.     defines = ['-DHAVE_CONFIG_H',
  141.            '-DPYTHONPATH=\\"$(PYTHONPATH)\\"']
  142.     includes = ['-I' + incldir, '-I' + binlib]
  143.  
  144.     # sanity check of directories and files
  145.     for dir in [prefix, exec_prefix, binlib, incldir] + extensions:
  146.         if not os.path.exists(dir):
  147.             usage('needed directory %s not found' % dir)
  148.         if not os.path.isdir(dir):
  149.             usage('%s: not a directory' % dir)
  150.     for file in [config_c_in, makefile_in] + supp_sources:
  151.         if not os.path.exists(file):
  152.             usage('needed file %s not found' % file)
  153.         if not os.path.isfile(file):
  154.             usage('%s: not a plain file' % file)
  155.     for dir in extensions:
  156.         setup = os.path.join(dir, 'Setup')
  157.         if not os.path.exists(setup):
  158.             usage('needed file %s not found' % setup)
  159.         if not os.path.isfile(setup):
  160.             usage('%s: not a plain file' % setup)
  161.  
  162.     # check that enough arguments are passed
  163.     if not args:
  164.         usage('at least one filename argument required')
  165.  
  166.     # check that file arguments exist
  167.     for arg in args:
  168.         if not os.path.exists(arg):
  169.             usage('argument %s not found' % arg)
  170.         if not os.path.isfile(arg):
  171.             usage('%s: not a plain file' % arg)
  172.  
  173.     # process non-option arguments
  174.     scriptfile = args[0]
  175.     modules = args[1:]
  176.  
  177.     # derive target name from script name
  178.     base = os.path.basename(scriptfile)
  179.     base, ext = os.path.splitext(base)
  180.     if base:
  181.         if base != scriptfile:
  182.             target = base
  183.         else:
  184.             target = base + '.bin'
  185.  
  186.     # Actual work starts here...
  187.  
  188.     dict = findmodules.findmodules(scriptfile, modules, path)
  189.     names = dict.keys()
  190.     names.sort()
  191.     print "Modules being frozen:"
  192.     for name in names:
  193.         print '\t', name
  194.  
  195.     backup = frozen_c + '~'
  196.     try:
  197.         os.rename(frozen_c, backup)
  198.     except os.error:
  199.         backup = None
  200.     outfp = open(frozen_c, 'w')
  201.     try:
  202.         makefreeze.makefreeze(outfp, dict)
  203.     finally:
  204.         outfp.close()
  205.     if backup:
  206.         if cmp.cmp(backup, frozen_c):
  207.             sys.stderr.write('%s not changed, not written\n' %
  208.                      frozen_c)
  209.             os.rename(backup, frozen_c)
  210.  
  211.     builtins = []
  212.     unknown = []
  213.     mods = dict.keys()
  214.     mods.sort()
  215.     for mod in mods:
  216.         if dict[mod] == '<builtin>':
  217.             builtins.append(mod)
  218.         elif dict[mod] == '<unknown>':
  219.             unknown.append(mod)
  220.  
  221.     addfiles = []
  222.     if unknown:
  223.         addfiles, addmods = \
  224.               checkextensions.checkextensions(unknown, extensions)
  225.         for mod in addmods:
  226.             unknown.remove(mod)
  227.         builtins = builtins + addmods
  228.     if unknown:
  229.         sys.stderr.write('Warning: unknown modules remain: %s\n' %
  230.                  string.join(unknown))
  231.  
  232.     builtins.sort()
  233.     infp = open(config_c_in)
  234.     backup = config_c + '~'
  235.     try:
  236.         os.rename(config_c, backup)
  237.     except os.error:
  238.         backup = None
  239.     outfp = open(config_c, 'w')
  240.     try:
  241.         makeconfig.makeconfig(infp, outfp, builtins)
  242.     finally:
  243.         outfp.close()
  244.     infp.close()
  245.     if backup:
  246.         if cmp.cmp(backup, config_c):
  247.             sys.stderr.write('%s not changed, not written\n' %
  248.                      config_c)
  249.             os.rename(backup, config_c)
  250.  
  251.     cflags = defines + includes + ['$(OPT)']
  252.     libs = []
  253.     for n in 'Modules', 'Python', 'Objects', 'Parser':
  254.         n = 'lib%s.a' % n
  255.         n = os.path.join(binlib, n)
  256.         libs.append(n)
  257.  
  258.     makevars = parsesetup.getmakevars(makefile_in)
  259.     somevars = {}
  260.     for key in makevars.keys():
  261.         somevars[key] = makevars[key]
  262.  
  263.     somevars['CFLAGS'] = string.join(cflags) # override
  264.     files = ['$(OPT)', config_c, frozen_c] + \
  265.         supp_sources +  addfiles + libs + \
  266.         ['$(MODLIBS)', '$(LIBS)', '$(SYSLIBS)']
  267.  
  268.     backup = makefile + '~'
  269.     try:
  270.         os.rename(makefile, backup)
  271.     except os.error:
  272.         backup = None
  273.     outfp = open(makefile, 'w')
  274.     try:
  275.         makemakefile.makemakefile(outfp, somevars, files, target)
  276.     finally:
  277.         outfp.close()
  278.     if backup:
  279.         if not cmp.cmp(backup, makefile):
  280.             print 'previous Makefile saved as', backup
  281.         else:
  282.             sys.stderr.write('%s not changed, not written\n' %
  283.                      makefile)
  284.             os.rename(backup, makefile)
  285.  
  286.     # Done!
  287.  
  288.     print 'Now run make to build the target:', target
  289.  
  290.  
  291. # Print usage message and exit
  292.  
  293. def usage(msg = None):
  294.     if msg:
  295.         sys.stderr.write(str(msg) + '\n')
  296.     sys.stderr.write(usage_msg)
  297.     sys.exit(2)
  298.  
  299.  
  300. main()
  301.